/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// import { index as xmlBuilder } from '../lib2/index.js';
import { defaults } from './defaults.js';

"use strict";
// let builder = xmlBuilder
let hasProp = {}.hasOwnProperty;
let requiresCDATA = function (entry) {
  return typeof entry === "string" && (entry.indexOf('&') >= 0 || entry.indexOf('>') >= 0 || entry.indexOf('<') >= 0);
};

let wrapCDATA = function (entry) {
  return "<![CDATA[" + (escapeCDATA(entry)) + "]]>";
};

let escapeCDATA = function (entry) {
  return entry.replace(']]>', ']]]]><![CDATA[>');
};


function Builder(opts) {
  var key, ref, value;
  this.options = {};
  ref = defaults["0.2"];
  for (key in ref) {
    if (!hasProp.call(ref, key)) continue;
    value = ref[key];
    this.options[key] = value;
  }
  for (key in opts) {
    if (!hasProp.call(opts, key)) continue;
    value = opts[key];
    this.options[key] = value;
  }
}

Builder.prototype.buildObject = function (rootObj) {
  var attrkey, charkey, render, rootElement, rootName;
  attrkey = this.options.attrkey;
  charkey = this.options.charkey;
  if ((Object.keys(rootObj).length === 1) && (this.options.rootName === defaults['0.2'].rootName)) {
    rootName = Object.keys(rootObj)[0];
    rootObj = rootObj[rootName];
  } else {
    rootName = this.options.rootName;
  }
  render = (function (_this) {
    return function (element, obj) {
      var attr, child, entry, index, key, value;
      if (typeof obj !== 'object') {
        if (_this.options.cdata && requiresCDATA(obj)) {
          element.raw(wrapCDATA(obj));
        } else {
          element.txt(obj);
        }
      } else if (Array.isArray(obj)) {
        for (index in obj) {
          if (!hasProp.call(obj, index)) continue;
          child = obj[index];
          for (key in child) {
            entry = child[key];
            element = render(element.ele(key), entry).up();
          }
        }
      } else {
        for (key in obj) {
          if (!hasProp.call(obj, key)) continue;
          child = obj[key];
          if (key === attrkey) {
            if (typeof child === "object") {
              for (attr in child) {
                value = child[attr];
                element = element.att(attr, value);
              }
            }
          } else if (key === charkey) {
            if (_this.options.cdata && requiresCDATA(child)) {
              element = element.raw(wrapCDATA(child));
            } else {
              element = element.txt(child);
            }
          } else if (Array.isArray(child)) {
            for (index in child) {
              if (!hasProp.call(child, index)) continue;
              entry = child[index];
              if (typeof entry === 'string') {
                if (_this.options.cdata && requiresCDATA(entry)) {
                  element = element.ele(key).raw(wrapCDATA(entry)).up();
                } else {
                  element = element.ele(key, entry).up();
                }
              } else {
                element = render(element.ele(key), entry).up();
              }
            }
          } else if (typeof child === "object") {
            element = render(element.ele(key), child).up();
          } else {
            if (typeof child === 'string' && _this.options.cdata && requiresCDATA(child)) {
              element = element.ele(key).raw(wrapCDATA(child)).up();
            } else {
              if (child == null) {
                child = '';
              }
              element = element.ele(key, child.toString()).up();
            }
          }
        }
      }
      return element;
    };
  })(this);
  // rootElement = builder.create(rootName, this.options.xmldec, this.options.doctype, {
  //   headless: this.options.headless,
  //   allowSurrogateChars: this.options.allowSurrogateChars
  // });
  return render(rootElement, rootObj).end(this.options.renderOpts);
};


export { Builder }